package demo.progress;

import com.alibaba.fastjson.JSON;
import demo.using.redis.RedisUtil;
import org.apache.commons.lang3.RandomUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author : GuoFei
 * @date : 2019/3/6 9:46
 */
public class ProgressRate {

    private static final Logger logger = LoggerFactory.getLogger("rate");

    private static ExecutorService showService = Executors.newSingleThreadExecutor();

    private static ExecutorService myService = new ThreadPoolExecutor(
            100,
            100,
            10,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(),
            new ThreadFactory() {
                private final AtomicInteger mCount = new AtomicInteger(1);

                public Thread newThread(Runnable r) {
                    return new Thread(r, "myRate # " + mCount.getAndIncrement());
                }
            },
            new MyRateException()
    );


    public static void main(String[] args) {
        System.out.println(JSON.toJSONString(RedisUtil.keys()));
        String key = "progress_rate";
        String sizeKey = "progress_rate_size";
        RedisUtil.delete(key);
        int size = 1000;
        showService.submit(() -> showRate(key, sizeKey));
        RedisUtil.set(sizeKey, String.valueOf(size));
        for (int i = 0; i < 1000; i++) {
            RedisUtil.sadd(key, String.valueOf(i));
            logger.info("添加【{}】任务", i);
            int index = i;
            myService.submit(() -> doTask(index, key));
        }
        showService.shutdown();
        myService.shutdown();
        while (!showService.isTerminated()) {
            sleep(1000);
        }
        RedisUtil.delete(key, sizeKey);
        logger.info("结束方法");
    }

    // 展示进度
    private static void showRate(String key, String sizeKey) {
        try {
            while (true) {
                sleep(1000);
                logger.info("                           查看进度");
                int doneNum = Math.toIntExact(RedisUtil.scard(key));
                int size = Integer.parseInt(RedisUtil.get(sizeKey));
                logger.info("                           当前任务进度【{}/{}】", (size-doneNum), size);
                if (doneNum == 0) {
                    logger.info("                          finish!!!");
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 执行业务
    private static void doTask(int i, String key) {
        logger.info("【{}】开始处理任务", i);
        try {
            Thread.sleep(RandomUtils.nextInt(1000, 10000));
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        logger.info("【{}】结束处理任务", i);
        RedisUtil.srem(key, String.valueOf(i));
        logger.info("【{}】删除任务", i);
    }

    // 业务类
    public static void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    // 拒绝策略
    static class MyRateException implements RejectedExecutionHandler {
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            new Thread(r, "new Thread # " + new Random().nextInt(1000)).start();
        }
    }

}
